package lco.validation;

import java.util.Hashtable;

import lco.cRLanguage.Assignment;
import lco.cRLanguage.IndexedVectorial;
import lco.cRLanguage.ScalarDeclaration;
import lco.cRLanguage.Size;
import lco.cRLanguage.Variable;
import lco.cRLanguage.VectorialDeclaration;

import org.eclipse.xtext.validation.Check;
 

public class CRLanguageJavaValidator extends AbstractCRLanguageJavaValidator {
	class DeclarationAttributes {
		public String name;
		public String type;
		public int x;
		public int y;
	}
	
	private Hashtable<String, DeclarationAttributes> variables = new Hashtable<String, DeclarationAttributes>();
	
	@Check
	public void checkVectorialDeclaration(VectorialDeclaration vd) {
		DeclarationAttributes da = new DeclarationAttributes();
		da.name = vd.getVariable().getName();
		da.type = vd.getType();
		da.x = vd.getX();
		da.y = vd.getY();
		variables.put(vd.getVariable().getName(), da);
	}
	
	@Check
	public void checkScalarDeclaration(ScalarDeclaration sd) {
		DeclarationAttributes da = new DeclarationAttributes();
		da.name = sd.getVariable().getName();
		da.type = sd.getType();
		variables.put(sd.getVariable().getName(), da);
	}
	
	public boolean checkIsScalar(Variable v) {
		DeclarationAttributes da = variables.get(v.getName());
		return da.x == 0 && da.y == 0;
	}
	
	public String getIndexedVectorialType(IndexedVectorial iv) {
		DeclarationAttributes da = variables.get(iv.getVariable().getName());
		String type = da.type;
		int dim = (da.x != 0 && da.y != 0)? 2 : 1;
		
		if (iv.getY() == null && iv.getX() == null) {
			return dim == 2? "array of array of " + type : "array of" + type;
		}
		if ((iv.getY() == null && dim == 2) || 
			(iv.getX() == null && dim == 1))
			return "array of " + type;
		else
			return type;
	}
	
	@Check
	public void checkAssignment(Assignment assignment) {
		Size size;
		String type;
		
		
		try {
			size = null;
			size = assignment.getSa().getExpr().getCallable().getMethod().getSize();
			type = (variables.get(assignment.getSa().getVar().getName()).type); 
			if (size != null &&  !type.equals("Int"))
				error("Size methods returns an Int type, tried to assign to " + type, null);
			if (size != null &&  !checkIsScalar(assignment.getSa().getVar()))
				error("Size methods returns an Int type, tried to assign to a vectorial variable", null);
		} catch (Exception e) {}
		
		
		try {
			size = null;
			size = assignment.getVa().getExpr().getCallable().getMethod().getSize();
			type = getIndexedVectorialType(assignment.getVa().getVar());
			if (size != null && !type.equals("Int"))
				error("Size methods returns an Int type, tried to assign to " + type, null);
		} catch (Exception e) {}
		
		
	}
}